using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Acme.BookStore.EntityFrameworkCore;
using Acme.BookStore.MultiTenancy;
using Acme.BookStore.Redis;
using OpenIddict.Validation.AspNetCore;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.Caching;
using Volo.Abp.Caching.StackExchangeRedis;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
using Volo.Abp.VirtualFileSystem;
using Volo.Abp.Security.Claims;
using Volo.Abp.UI.Navigation.Urls;
using System.Threading.Tasks;
using Swashbuckle.AspNetCore.SwaggerUI;

namespace Acme.BookStore;

[DependsOn(
    typeof(BookStoreHttpApiModule),
    typeof(AbpAutofacModule),
    typeof(AbpAspNetCoreMultiTenancyModule),
    typeof(BookStoreApplicationModule),
    typeof(BookStoreEntityFrameworkCoreModule),
    typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule),
    typeof(AbpAccountWebOpenIddictModule),
    typeof(AbpAspNetCoreSerilogModule),
    typeof(AbpSwashbuckleModule),
    typeof(AbpCachingStackExchangeRedisModule)
)]
public class BookStoreHttpApiHostModule : AbpModule
{
    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        PreConfigure<OpenIddictBuilder>(builder =>
        {
            builder.AddValidation(options =>
            {
                options.AddAudiences("BookStore");
                options.UseLocalServer();
                options.UseAspNetCore();
            });
        });
    }

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        var hostingEnvironment = context.Services.GetHostingEnvironment();

        ConfigureAuthentication(context);
        ConfigureBundles();
        ConfigureUrls(configuration);
        ConfigureConventionalControllers();
        ConfigureVirtualFileSystem(context);
        ConfigureCors(context, configuration);
        ConfigureSwaggerServices(context, configuration);
        
        // 配置缓存（Redis或内存缓存）
        ConfigureCache(context, configuration);
    }

    private void ConfigureCache(ServiceConfigurationContext context, IConfiguration configuration)
    {
        // 不在这里初始化logger，改用其他方式记录日志qi
        
        // 配置ABP缓存选项
        Configure<AbpDistributedCacheOptions>(options =>
        {
            options.KeyPrefix = "BookStore:";
        });
        
        // 读取Redis配置
        var isRedisEnabled = configuration["Redis:IsEnabled"];
        
        if (isRedisEnabled?.Equals("true", StringComparison.OrdinalIgnoreCase) == true)
        {
            // 配置Redis缓存
            Configure<RedisCacheOptions>(options =>
            {
                var redisConfiguration = configuration["Redis:Configuration"];
                if (!string.IsNullOrEmpty(redisConfiguration))
                {
                    options.Configuration = redisConfiguration;
                }
            
                var instanceName = configuration["Redis:InstanceName"];
                if (!string.IsNullOrEmpty(instanceName))
                {
                    options.InstanceName = instanceName;
                }
                
                // 创建完整的配置选项
                options.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions
                {
                    EndPoints = { redisConfiguration },
                    ConnectTimeout = int.TryParse(configuration["Redis:ConnectionTimeout"], out var connectionTimeout) ? connectionTimeout : 5000,
                    ConnectRetry = int.TryParse(configuration["Redis:ConnectRetry"], out var connectRetry) ? connectRetry : 3,
                    AbortOnConnectFail = false,
                    KeepAlive = int.TryParse(configuration["Redis:KeepAlive"], out var keepAlive) ? keepAlive : 60,
                    SyncTimeout = int.TryParse(configuration["Redis:SyncTimeout"], out var syncTimeout) ? syncTimeout : 10000
                };
            });
            
            // 不使用logger，使用控制台输出
            Console.WriteLine("已配置Redis分布式缓存");
        }
        else
        {
            // 使用内存缓存
            context.Services.AddDistributedMemoryCache();
            Console.WriteLine("已配置内存缓存（未启用Redis）");
        }
    }

    private void ConfigureAuthentication(ServiceConfigurationContext context)
    {
        context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
        context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
        {
            options.IsDynamicClaimsEnabled = true;
        });
    }

    private void ConfigureBundles()
    {
        Configure<AbpBundlingOptions>(options =>
        {
            options.StyleBundles.Configure(
                LeptonXLiteThemeBundles.Styles.Global,
                bundle =>
                {
                    bundle.AddFiles("/global-styles.css");
                }
            );
        });
    }

    private void ConfigureUrls(IConfiguration configuration)
    {
        Configure<AppUrlOptions>(options =>
        {
            options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
            options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"]?.Split(',') ?? Array.Empty<string>());

            options.Applications["Angular"].RootUrl = configuration["App:ClientUrl"];
            options.Applications["Angular"].Urls[AccountUrlNames.PasswordReset] = "account/reset-password";
        });
    }

    private void ConfigureVirtualFileSystem(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();

        if (hostingEnvironment.IsDevelopment())
        {
            Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.ReplaceEmbeddedByPhysical<BookStoreDomainSharedModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}Acme.BookStore.Domain.Shared"));
                options.FileSets.ReplaceEmbeddedByPhysical<BookStoreDomainModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}Acme.BookStore.Domain"));
                options.FileSets.ReplaceEmbeddedByPhysical<BookStoreApplicationContractsModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}Acme.BookStore.Application.Contracts"));
                options.FileSets.ReplaceEmbeddedByPhysical<BookStoreApplicationModule>(
                    Path.Combine(hostingEnvironment.ContentRootPath,
                        $"..{Path.DirectorySeparatorChar}Acme.BookStore.Application"));
            });
        }
    }

    private void ConfigureConventionalControllers()
    {
        Configure<AbpAspNetCoreMvcOptions>(options =>
        {
            options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly);
        });
    }

    private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddAbpSwaggerGenWithOAuth(
            configuration["AuthServer:Authority"]!,
            new Dictionary<string, string>
            {
                    {"BookStore", "BookStore API"}
            },
            options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = "BookStore API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);
                options.CustomSchemaIds(type => type.FullName);
                
                // 添加XML注释文件
                var xmlPath = Path.Combine(AppContext.BaseDirectory, "Acme.BookStore.HttpApi.xml");
                if (File.Exists(xmlPath))
                {
                    options.IncludeXmlComments(xmlPath);
                }
                
                var httpApiClientXmlPath = Path.Combine(AppContext.BaseDirectory, "Acme.BookStore.HttpApi.Client.xml");
                if (File.Exists(httpApiClientXmlPath))
                {
                    options.IncludeXmlComments(httpApiClientXmlPath);
                }
                
                var applicationContractsXmlPath = Path.Combine(AppContext.BaseDirectory, "Acme.BookStore.Application.Contracts.xml");
                if (File.Exists(applicationContractsXmlPath))
                {
                    options.IncludeXmlComments(applicationContractsXmlPath);
                }
                
                // 允许使用授权头
                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey
                });
            });
    }

    private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder =>
            {
                var corsOrigins = configuration["App:CorsOrigins"];
                if (!string.IsNullOrEmpty(corsOrigins))
                {
                    var origins = corsOrigins.Split(",", StringSplitOptions.RemoveEmptyEntries);
                    var originsList = new List<string>();
                    foreach (var origin in origins)
                    {
                        originsList.Add(origin.RemovePostFix("/"));
                    }
                    
                    // 添加本地开发地址
                    originsList.Add("https://localhost:44359");
                    originsList.Add("http://localhost:44359");
                    
                    builder.WithOrigins(originsList.ToArray());
                }
                else
                {
                    builder.AllowAnyOrigin();
                }
                
                builder.WithAbpExposedHeaders()
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });
    }

    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAbpRequestLocalization();

        if (!env.IsDevelopment())
        {
            app.UseErrorPage();
        }

        app.UseCorrelationId();
        app.MapAbpStaticAssets();
        app.UseRouting();
        app.UseCors();
        app.UseAuthentication();
        app.UseAbpOpenIddictValidation();

        if (MultiTenancyConsts.IsEnabled)
        {
            app.UseMultiTenancy();
        }
        app.UseUnitOfWork();
        app.UseDynamicClaims();
        app.UseAuthorization();

        app.UseSwagger(options => 
        {
            options.PreSerializeFilters.Add((swagger, httpReq) =>
            {
                // 设置服务器URL
                swagger.Servers = new List<OpenApiServer> 
                { 
                    new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}" } 
                };
            });
        });
        
        app.UseAbpSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "BookStore API");
            c.DefaultModelsExpandDepth(-1); // 隐藏Models
            c.DocExpansion(DocExpansion.None); // 默认折叠API

            var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
            c.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
            c.OAuthScopes("BookStore");
            
            // 增加请求超时时间 - 使用标准的Swagger UI选项设置
            c.EnableDeepLinking();
            c.DisplayOperationId();
            c.DefaultModelRendering(ModelRendering.Example);
            c.ShowExtensions();
            c.EnableValidator();
            
            // 使用直接配置Javascript
            c.InjectJavascript("/swagger/ui/abp.js");
            c.InjectJavascript("/swagger/ui/swagger-custom.js");
        });

        app.UseAuditing();
        app.UseAbpSerilogEnrichers();
        app.UseConfiguredEndpoints();
    }
}
